const path = require('path');
const esbuild = require('esbuild');

const { readFileAsync } = require('../lib/fsUtil');
const { THIRD_MODULE_PATH_REGEX, INNER_MODULE_PATH_REGEX, IMPORT_TYPE_REGEX } = require('../lib/regexUtil');
const refactorLodash = require('../refactor/refactorLodash');
const replaceEnv = require('../refactor/replaceEnv');
const removeCommets = require('../refactor/removeCommets');

const { getDomain, DomainConfig } = require('../lib/domain.config.js');

/**
 * 删除未使用的Import
 * @param {string} code
 */
const removeUnusedImport = async (code, filepath) => {
  try {
    const result = await esbuild.transform(code, {
      target: ['es2020'],
      sourcemap: false,
      charset: 'utf8',
      loader: /tsx$/.test(filepath) ? 'tsx' : 'ts',
      tsconfigRaw: {
        compilerOptions: {
          importsNotUsedAsValues: 'remove',
        },
      },
    });

    return result.code;
  } catch (err) {
    console.warn(['', filepath, '', err.message].join('\n'))
    return code;
  }
};

/** @param {string} filepath */
module.exports.transform = async (filepath) => {
  const [rootContext] = filepath.split('/src/');
  const source = await readFileAsync(filepath, { encoding: 'utf8' });

  let newSource = await removeUnusedImport(source, filepath);

  const ExposesCache = Object.fromEntries(Object.keys(DomainConfig).map((domain) => [domain, []]));

  const context = {
    context: path.dirname(filepath),
    rootContext,
    resourcePath: filepath,
    ExposesCache,
  };

  newSource = refactorLodash.call(context, newSource);
  newSource = replaceImportModulePath.call(context, newSource);

  return ExposesCache;
};

/**
 * 替换领域路径
 * @param {string} source
 */
function replaceImportModulePath(source) {
  const { context: fileDirPath, resourcePath: filePath, rootContext, ExposesCache } = this;
  const srcfullpath = path.resolve(rootContext, 'src');
  const typesDirPath = path.resolve(rootContext, 'src/types/');

  // 源码前添加一个空格是为了使正则可以捕获到全部import,因为正则中使用了反向肯定断言 ?<=\W
  // 如果不加空格， 首行 import 无法捕获
  let newSource = '\t\t\t\t' + source;

  // 忽略非src目录文件
  if (filePath.includes(srcfullpath) === false) return source;
  // 忽略 src/types
  if (filePath.includes(typesDirPath) === true) return source;
  // 忽略文件列表
  if (
    ['src/apphub/routers/router-map.ts', 'src/apphub/routers/router-map-extend.ts', '/src/types/'].some((file) => {
      return new RegExp(file).test(filePath);
    })
  ) {
    return source;
  }

  // 删除注释
  newSource = removeCommets(newSource);

  // mobx/lib/mobx mobx/lib/index ==> mobx

  // 删除import type
  newSource = newSource.replace(IMPORT_TYPE_REGEX, '');

  // 环境变量替换
  newSource = replaceEnv(newSource);

  // 为所有 node_modules 下的模块添加 thirdlib/ 前辍
  newSource = newSource.replace(THIRD_MODULE_PATH_REGEX, (res) => {
    let len = res.length;
    let left = res[0];
    let mid = res.slice(1, len - 1);
    let right = res[len - 1];

    // http url 地址不处理
    if (/https?:\/\//.test(mid)) {
      return res;
    }

    // 远程私有模块
    if (
      Object.entries(DomainConfig).some(([domain, domainDir]) => {
        if (mid.startsWith(domainDir)) {
          ExposesCache[domain].push(mid);
          return true;
        }
        return false;
      })
    ) {
      return res;
    }

    // @remote/apphub ==> src/apphub
    // @remote/appService ==> src/apphub
    if (/^@remote\//m.test(mid)) {
      if((/^@remote\/(apphub|components|modules|hkj|thirdlib|voucher-common\/)/m.test(mid))) {
        mid = mid.replace('@remote/', 'src/');
        ExposesCache['thirdlib'].push(mid);
        return left + mid + right;
      }
      return left + mid + right;
    }

    // 第三方库 例如： react, react-dom, @chanjet/....
    ExposesCache['thirdlib'].push(mid);

    return left + 'thirdlib/' + mid + right;
  });

  // 领域路径替换
  newSource = newSource.replace(INNER_MODULE_PATH_REGEX, (res) => {
    let len = res.length;
    let left = res[0];
    let mid = res.slice(1, len - 1);
    let right = res[len - 1];

    let moduleImportPath = mid;
    // require(`../statics/images/${name}.png`)
    let lastSlash = mid.slice(-1) === '/' ? '/' : '';

    // 相对路径替换为src路径
    if (mid.startsWith('.')) {
      moduleImportPath = path.resolve(fileDirPath, mid).replace(rootContext + '/', '');
    }

    // replace // to /
    moduleImportPath = moduleImportPath.replace(/\/\//, '/');
    // 删除后辍 /index && .tsx .ts
    moduleImportPath = moduleImportPath.replace(/(\/index(\.tsx?)?|\.tsx?)$/m, '');

    // 模块绝对路径
    const moduleFullPath = path.resolve(rootContext, moduleImportPath);

    // 当前文件所在域
    const fileDomain = getDomain(filePath, rootContext);
    // 引用模块所在域
    const moduleDomain = getDomain(moduleFullPath, rootContext);

    if (moduleDomain) {
      // 跨域引用
      if (fileDomain.name !== moduleDomain.name && moduleDomain.name !== null) {
        // 导出 src路径
        if (ExposesCache[moduleDomain.name]) {
          ExposesCache[moduleDomain.name].push(moduleImportPath);
        }
        // 转换为域名前辍
        moduleImportPath = moduleFullPath.replace(moduleDomain.fullpath, moduleDomain.srcPath);
      }
      // 同域引用
      if (fileDomain.name === moduleDomain.name && moduleDomain.name !== null) {
        const relativePath = path.relative(fileDirPath, moduleFullPath);
        moduleImportPath = relativePath.startsWith('..') ? relativePath : './' + relativePath;
      }
    }

    return left + moduleImportPath + lastSlash + right;
  });
  return newSource;
}
